#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "hash2.h"

ULONG hash(const DATA_ELEM *data_elem)
{
	assert(data_elem->key >= 0);
	return data_elem->key % HASH_TABLE_SIZE;
}

int init_hash(HASH_TABLE **hash_table)
{	
	HASH_TABLE *temp_table = NULL;
	DATA_ELEM *temp_array = NULL;

	assert(NULL == *hash_table);
	
	temp_table = (HASH_TABLE *)malloc(sizeof(HASH_TABLE));
	if(NULL == temp_table)
	{
		return -1;
	}
	memset(temp_table, 0, sizeof(HASH_TABLE));
	temp_table->size = HASH_TABLE_SIZE;
	temp_table->elem_count = 0;
	temp_array = (DATA_ELEM *)malloc(sizeof(DATA_ELEM) * HASH_TABLE_SIZE);
	if(NULL == temp_array)
	{
		free(temp_table);
		temp_table = NULL;
		return -2;
	}
	memset(temp_array, -1, sizeof(DATA_ELEM) * HASH_TABLE_SIZE);
	temp_array[0].key = 0;
	temp_table->array = temp_array;
	*hash_table = temp_table;

	return 0;
	
}

int free_hash(HASH_TABLE *hash_table)
{
	HASH_TABLE *temp_table = NULL;
	DATA_ELEM *temp_array = NULL;
	
	assert(NULL != hash_table);

	temp_array = hash_table->array;
	temp_table = hash_table;
	free(temp_array);
	temp_array = NULL;
	free(temp_table);
	temp_table = NULL;
	return 0;
	
}

/*
return value:
        0:  search success;
        -1: serch failed, the item is not in the hash table;
        -2: serch failed, conflict beyond capacity;
        -3: upexpected result.
*/
int search_hash(const HASH_TABLE *hash_table, const DATA_ELEM *data_elem, ULONG *index, ULONG *conflict_count)
{
	ULONG temp_index = 0;
	ULONG temp_conflict_count = 0;
	
	assert(NULL != hash_table);
	assert(NULL != data_elem);
	assert(NULL != index);
	assert(NULL != conflict_count);

	temp_index = hash(data_elem);
	
	while(hash_table->array[temp_index].key != data_elem->key && hash_table->array[temp_index].key != -1)
	{
		if(temp_conflict_count > HASH_TABLE_SEARCH_CONFLICT_TIMES_CAPACITY)
		{
			return -2;
		}
		temp_index = (temp_index + 1) % HASH_TABLE_SIZE;
		temp_conflict_count++;
	}

	if(hash_table->array[temp_index].key == data_elem->key)
	{
		*index = temp_index;
		*conflict_count = temp_conflict_count;
		return 0;
	}
	else
	{
		if(hash_table->array[temp_index].key == -1)
		{
			*index = temp_index;
			*conflict_count = temp_conflict_count;
			return -1;
		}

		printf("Exceptional search result!\n");
		return -3;
	}
}

int insert_elem_to_hash(HASH_TABLE *hash_table, DATA_ELEM *data_elem)
{
	ULONG temp_index = 0;
	ULONG temp_conflict_count = 0;
	int result = 0;

	assert(NULL != hash_table);
	assert(NULL != data_elem);

	result = search_hash(hash_table, data_elem, &temp_index, &temp_conflict_count);
	if(!result)
	{
		return -2;
	}
	else if(-1 == result)
	{
		hash_table->array[temp_index].key = data_elem->key;
		hash_table->array[temp_index].data = data_elem->data;
		hash_table->elem_count++;
		//memcpy(hash_table->array[temp_index].data, data_elem->data, sizeof(data_elem->data));
		return 0;
	}
	else if(-2 == result)
	{
		return -3;
	}
	else
	{
		return -1;
	}
}

/*
int create_hash_table(const DataType *key_array)
{
	int i = 0;
	while(0 != key_array[i])
	{
		if(search_hash()
		{
			
		}
	}
}
*/

int delete_elem_from_hash(HASH_TABLE *hash_table, DATA_ELEM *data_elem)
{
	return 0;
}

void display_hash_table(HASH_TABLE *hash_table)
{
	int i;
	for(i = 0; i != hash_table->size; ++i)
	{
		printf("%d ", hash_table->array[i].key);
	}
	printf("\n");

}
